/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GlbLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_06_01			*/
/*	File:		GlbSet.cpp			*/
/********************************************************/

#include "GlbSet.h"

namespace GlbCls
{

CGlbSet::CGlbSet()
{
	m_ulSize = 0;
	m_ulCount = 0;
	m_pSet = NULL;
	m_pCompare = NULL;
}

CGlbSet::~CGlbSet()
{
	m_ulSize = 0;
	m_ulCount = 0;
	m_pSet = NULL;
	m_pCompare = NULL;
}

void* CGlbSet::GlbSetGetSet()
{
	return m_pSet;
}

ULONG CGlbSet::GlbSetGetSize()
{
	return m_ulSize;
}

ULONG CGlbSet::GlbSetGetCount()
{
	return m_ulCount;
}

GlbSetCompPtr CGlbSet::GlbSetGetCompare()
{
	return m_pCompare;
}

void CGlbSet::GlbSetPutSet(void* pSet)
{
	m_pSet = pSet;

	return;
}

void CGlbSet::GlbSetPutSize(ULONG ulSize)
{
	m_ulSize = ulSize;

	return;
}

void CGlbSet::GlbSetPutCount(ULONG ulCount)
{
	m_ulCount = ulCount;

	return;
}

void CGlbSet::GlbSetDestroy()
{
	m_ulSize = 0;
	m_ulCount = 0;
	m_pCompare = NULL;
	if (NULL != m_pSet) {
		free(m_pSet);
		m_pSet = NULL;
	}
}

void CGlbSet::GlbSetReset(ULONG ulTotal)
{
	m_ulCount = 0;
	memset(m_pSet, '\0', ulTotal * m_ulSize);

	return;
}

void CGlbSet::GlbSetReset(ULONG ulTotal, ULONG ulSize)
{
	m_ulCount = 0;
	memset(m_pSet, '\0', ulTotal * ulSize);

	return;
}

int CGlbSet::GlbSetInit(ULONG ulTotal, ULONG ulSize)
{
	int iReturn = GLB_SUCCESS;

	m_ulSize = ulSize;
	m_pSet = (void*)malloc(ulTotal * ulSize);
	if (NULL != m_pSet) {
		memset(m_pSet, '\0', ulTotal * ulSize);
	}
	else {
		GLB_ERROR("%s\n", strerror(errno));
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

void CGlbSet::GlbSetClone(CGlbSet& CSet)
{
	if (GLB_SUCCESS == GlbSetInit(CSet.GlbSetGetCount(), CSet.GlbSetGetSize())) {
		m_ulSize = CSet.GlbSetGetSize();
		m_ulCount = CSet.GlbSetGetCount();
		m_pCompare = CSet.GlbSetGetCompare();
		memcpy(m_pSet, CSet.GlbSetGetSet(), m_ulCount * m_ulSize);
	}

	return;
}

void CGlbSet::GlbSetCompare(GlbSetCompPtr pCompare)
{
	m_pCompare = pCompare;

	return;
}

void* CGlbSet::GlbSetIndexGet(ULONG ulIndex)
{
	void* pReturn = NULL;

	return pReturn = (UCHAR*)m_pSet + ulIndex * m_ulSize;
}

void CGlbSet::GlbSetIndexErase(ULONG ulIndex)
{
	memset((UCHAR*)m_pSet + ulIndex * m_ulSize, '\0', m_ulSize);

	return;
}

ULONG CGlbSet::GlbSetIndexPut(ULONG ulIndex, void* pData)
{
	memcpy((UCHAR*)m_pSet + ulIndex * m_ulSize, pData, m_ulSize);
	if (ulIndex >= m_ulCount) {
		m_ulCount += 1;
	}

	return m_ulCount;
}

void CGlbSet::GlbSetOrder()
{
	UCHAR* pucSrc = NULL;
	UCHAR* pucDst = NULL;

	pucSrc = pucDst = (UCHAR*)m_pSet;
	while ((pucSrc - (UCHAR*)m_pSet) / m_ulSize < m_ulCount) {
		while (false == GlbSetIndexIsNull(pucDst) && (pucDst - (UCHAR*)m_pSet) / m_ulSize < m_ulCount) pucSrc = (pucDst += m_ulSize);
		while (true == GlbSetIndexIsNull(pucSrc) && (pucSrc - (UCHAR*)m_pSet) / m_ulSize < m_ulCount) pucSrc += m_ulSize;
		if ((pucSrc - (UCHAR*)m_pSet) / m_ulSize < m_ulCount) {
			memcpy(pucDst, pucSrc, m_ulSize);
			memset(pucSrc, '\0', m_ulSize);
		}
	}
	m_ulCount = (pucDst - (UCHAR*)m_pSet) / m_ulSize;

	return;
}

void CGlbSet::GlbSetSort()
{
	qsort(m_pSet, m_ulCount, m_ulSize, *m_pCompare);

	return;
}

void CGlbSet::GlbSetUniq()
{
	UCHAR* pucSrc = (UCHAR*)m_pSet;
	UCHAR* pucDst = pucSrc + m_ulSize;

	GlbSetSort();
	while ((pucDst - (UCHAR*)m_pSet) / m_ulSize < m_ulCount) {
		if (GLB_SUCCESS == memcmp(pucSrc, pucDst, m_ulSize)) {
			memset(pucDst, '\0', m_ulSize);
		}
		else {
			pucSrc = pucDst;
		}
		pucDst += m_ulSize;
	}
	GlbSetOrder();

	return;
}

long CGlbSet::GlbSetIndex(void* pKey)
{
	void* pReturn = NULL;
	long lIndex = GLB_FAILURE;

	if (NULL != (pReturn = bsearch(pKey, m_pSet, m_ulCount, m_ulSize, *m_pCompare))) {
		lIndex = ((UCHAR*)pReturn - (UCHAR*)m_pSet) / m_ulSize;
	}

	return lIndex;
}

void* CGlbSet::GlbSetSearch(void* pKey)
{
	return bsearch(pKey, m_pSet, m_ulCount, m_ulSize, *m_pCompare);
}

int CGlbSet::GlbSetSearch(void* pKey, void* pData)
{
	void* pReturn = NULL;

	if (NULL != (pReturn = bsearch(pKey, m_pSet, m_ulCount, m_ulSize, *m_pCompare))) {
		memcpy(pData, pReturn, m_ulSize);
	}
	else {
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

bool CGlbSet::GlbSetIndexIsNull(UCHAR* pucCur)
{
	bool bReturn = true;
	UCHAR* pucBase = pucCur;

	while ((ULONG)(pucCur - pucBase) < m_ulSize) {
		if ('\0' != *pucCur ++) {
			bReturn = false;
			break;
		}
	}

	return bReturn;
}

} /* GlbCls */
